Skip to content

docs(rest): state the direction the read predicate rules on at the /published door - #16586

Merged
os-sales merged 1 commit into
mainfrom
claude/issue-16032-published-door-scope-comment
Sep 7, 2026
Merged

docs(rest): state the direction the read predicate rules on at the /published door#16586
os-sales merged 1 commit into
mainfrom
claude/issue-16032-published-door-scope-comment

Conversation

@claude

@claude claude Bot commented Sep 7, 2026

Copy link
Copy Markdown
Contributor

Fixes #16032

The finding

The GET /meta/:type/:name/published handler in packages/rest/src/rest-server.ts carried a paragraph arguing that handing getMetaItemLayered the RAW tenant "is right for a READ", because that method's overlay layer is org-scoped-first and THEN env-wide, so the door was "fail-open in the safe direction" and "nothing that resolves today stops resolving".

Fail-open in that direction is precisely what organizationIdForMetaRead was written to refute. Its own docblock in packages/metadata-core/src/meta-write-org-scope.ts names the shorter fix as wrong, and the callee's #14907 block re-states it against this very door: naming the org on a type the registry does not declare per-org overridable resurrects, on the read side, the phantom rows #6190 stopped minting.

Since #14907 the callee gates. getMetaItemLayered resolves organizationIdForMetaRead(request.type, request.organizationId) itself, deliberately placed AFTER its canonical fold. So the raw tenant here is correct — but for a different reason than the one the comment gave, and the reason the comment gave is the one the predicate rules against.

Why this was a card and not a tidy-up

The #14907 card and its triage comment both recorded that this door already gates. Measured, it does not — and the comment is why. It reads as a deliberate, reasoned decision, so an enumeration that greps for the predicate name and then reads the surrounding prose comes away satisfied. Two seats in the same series inherited the same wrong reading from it. A self-consistent wrong comment costs far more than an obviously stale one, because it manufactures wrong census results.

Behaviour is correct today and there is no security consequence, which is why the card is p2.

The change

Comment-only, and line-count-neutral: 8 comment lines out, 8 comment lines in, no executable statement touched.

  • The new text states the direction the predicate actually rules on, rather than deleting a stale sentence.
  • The #8805 half above it is untouched and still true: this door really can produce a tier-A org-scoped publish and really must serve it back.
  • The "Still NOT the forbidden seam" opening is untouched.
  • No organizationIdForMetaRead call is added here. Computing the predicate on req.params.type (raw) would be the #10340 defect, because declaresOrgOverride answers false for the URL-only spellings; the fold is what makes it safe, and the callee already does it.

Verification

Comment-only, proved mechanically. Every added and removed line in the diff matches a whole-line // comment: 16 changed lines, 0 non-comment changed lines.

Line-count-neutral, so no absolute-line anchor moves. content/docs/permissions/system-context.mdx anchors this file at :1858, :1887, :1890, :5520, :6977, :7225, :7656, :7849 — all above the edited block, and the file's total line count is unchanged at 13443.

node scripts/check-system-context-census.mjs exits 0. That green is verified against a non-zero control rather than trusted: inserting one line at :100 (well above the anchored region), rebuilding nothing, reddens the gate to exit 1 with 12 structural errors naming exactly those rest-server.ts anchors — 6 site-without-a-row and 6 anchor-is-not-a-read-site. The mutation was proved on disk by marker count and by blob hash, and the restore proved byte-identical to the HEAD blob before the second leg ran.

Nothing is published, so skip-changeset is applied rather than a changeset written. @objectstack/rest publishes [dist, README.md, CHANGELOG.md]. Probing all six built artifacts (index.js, index.cjs, both .maps, index.d.ts, index.d.cts) finds zero occurrences of the edited comment's text, and both sourcemaps have sourcesContent ABSENT. The probe is verified by a non-zero control: an unrelated // prose comment from packages/rest/src/error-response.ts:903 is found in index.js and index.cjs, so line comments inside function bodies do reach dist — this one simply does not.

Stronger still, the built output is byte-identical across the diff. Building @objectstack/rest at the branch base and at HEAD produces the same sha256 for all six artifacts. turbo ls --affected names 19 packages, but 18 of them are reachable only through this package's emitted surface, which did not move.

Gates. node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack --commands derived 42 commands; reconciliation with --ran reports 42 derived, 42 run, 0 UNRUN. 41 exit 0. One is NOT MEASURED, never a pass: pnpm check:dual-build-cjs-loads exits 3 PREREQUISITE NOT MET because it reads built output and 43 packages have no dist/.

The 39 artifact rosters were run separately: 35 exit 0, 4 NOT MEASURED — pnpm check:published-readme-exports (exit 3, PREREQUISITE NOT MET), check:react-declaration-parity (exit 1, MANIFEST is not set, an on-demand gate needing an objectui manifest dump), and check-single-claim-paths.mjs plus check-partof-closing-keyword.mjs (exit 2, NOT WIRED, both need PR context supplied by their own workflows).

Tests. pnpm --filter @objectstack/rest exec vitest run --maxWorkers=2 — 188 test files, 3198 tests, all passed. pnpm --filter @objectstack/rest typecheck exits 0, including check:test-typecheck over tsconfig.test.json. Repo-wide pnpm lint was run in full and exits 0, so no narrowing is claimed.

No test was added: the diff has no executable delta to cover, and the byte-identical dist is the measurement that says so.

验收备注

  • Read as a family, not fixed here. #15621 (the getMetaItems docblock, PR docs(metadata-protocol): the getMetaItems gate enumerates six rest-server.ts call sites, not five, and names the transitive diagnostics door #16117 open) and #15620 (the /references org-scope block) are the same shape — a caller-side comment reasoning about read scope, written before the callee-side gate existed. Only this card's door is touched. Those two are not addressed here and remain open.
  • noted, not filed: the dispatch's stated mechanism for the changeset decision — that esbuild "keeps leading block comments while dropping line comments inside function bodies" — is not what this tree does. Line comments inside function bodies do survive into dist when attached to a preserved statement (the control above is one). The conclusion is unchanged and now rests on a measurement rather than on that rule. This is an observation about a dispatch note, not a repo defect, so no card.
  • noted, not filed: tsup emits "zodIssuesToFields" is imported from external module "@objectstack/spec/api" but never used in "src/rest-server.ts" on every build of this package. Pre-existing on the branch base, unrelated to this diff, and a lint-shaped observation rather than a reproducible defect, so it is not a card under Prime Directive 10.

🤖 Generated with Claude Code

https://claude.ai/code/session_01YFY46JydE1gMxQG1TqBcMZ


Generated by Claude Code

…ublished door

The `GET /meta/:type/:name/published` handler's comment argued that passing
the RAW tenant "is right for a READ" because `getMetaItemLayered`'s overlay
lookup is org-scoped-first then env-wide, so "nothing that resolves today
stops resolving". That fail-open direction is precisely the reasoning
`organizationIdForMetaRead` was written to refute: an org named on a type the
registry does not declare per-org overridable resurrects the phantom rows
#6190 stopped minting.

Since #14907 the callee gates: `getMetaItemLayered` resolves
`organizationIdForMetaRead` itself, AFTER its canonical fold. So the raw
tenant is correct here for a different reason than the one stated, and this
door must NOT pre-gate — `req.params.type` is unfolded, and gating on it is
the #10340 defect.

Because the old prose read as a deliberate, reasoned decision to gate, two
successive enumerations in the same series recorded this door as already
gating when it does not. The `#8805` half above is untouched and still true.

Comment-only and line-count-neutral: 8 comment lines out, 8 in, no
executable change, so the absolute-line anchors in
`content/docs/permissions/system-context.mdx` cannot move.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01YFY46JydE1gMxQG1TqBcMZ
@claude claude Bot added the skip-changeset PR has no user-facing published change; bypasses the changeset gate label Sep 7, 2026
@github-actions github-actions Bot added the size/s label Sep 7, 2026
@github-actions

github-actions Bot commented Sep 7, 2026

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

⚠️ 1 changed file(s) yielded no anchor (packages/rest/src/rest-server.ts), so the pages documenting them are NOT COVERED by this run — this is not a clean bill of health for those files. Nothing else in this diff resolved to a documentable surface (no symbol, route or SDK anchor derived from 1 changed package(s)).

What this run could not see
  • 1 changed file(s) yielded no anchor (packages/rest/src/rest-server.ts) — pages documenting those are invisible to this run
  • a page that states a rule by its inputs shares no identifier with the emitter that implements the rule, so an emitter-only diff cannot list it — not on this run and not on any run. Measured on fix(driver-sql): emit varchar(maxLength) for a text field a declared index keys on #11430: content/docs/protocol/objectql/types.mdx documents the text-family column mapping by the ObjectQL type names it maps FROM (text / textarea / html) while the diff changed createColumn; it went unlisted, and it was the page that diff falsified, in four places. No shared token exists to detect this on, so a rule your change carries has to be re-read by hand in the pages that restate it.

Coarse fallback — 13 page(s) merely mention a changed package (the pre-#9192 predicate, kept for the deliberately-wide backstop): node scripts/docs-audit/affected-docs.mjs --json f2f6684cd5e93032ed5d82a1848784b6026a8a03packageMentionDocs.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size/s skip-changeset PR has no user-facing published change; bypasses the changeset gate

Projects

None yet

2 participants